﻿(*                  FnSharp              

   Base class library extensions and frameworks aimed 
   specifically at improving F# developers lives!

   Written by: Huw Simpson
   License: Microsoft Public License (Ms-PL) 
   Available at: http://fnsharp.codeplex.com

*)
namespace FnSharp.Fundamental.CommandLine
    open System
    open System.Reflection
    open Microsoft.FSharp.Reflection
    open Newtonsoft.Json

    module internal Json =
        // Taken from https://github.com/robertpi/FsRavenDbTools/blob/master/src/FsRavenDbTools/Converters.fs (Robert Pickering)
        type OptionTypeConverter() =
            inherit JsonConverter()
            override x.CanConvert(typ:Type) =
                typ.IsGenericType && 
                    typ.GetGenericTypeDefinition() = typedefof<option<OptionTypeConverter>>

            override x.WriteJson(writer: JsonWriter, value: obj, serializer: JsonSerializer) =
                if value <> null then
                    let t = value.GetType()
                    let fieldInfo = t.GetField("value", System.Reflection.BindingFlags.NonPublic ||| System.Reflection.BindingFlags.Instance)
                    let value = fieldInfo.GetValue(value)
                    serializer.Serialize(writer, value)

            override x.ReadJson(reader: JsonReader, objectType: Type, existingValue: obj, serializer: JsonSerializer) = 
                let cases = Microsoft.FSharp.Reflection.FSharpType.GetUnionCases(objectType)
                let t = objectType.GetGenericArguments().[0]
                let t = 
                    if t.IsValueType then 
                        let nullable = typedefof<Nullable<int>> 
                        nullable.MakeGenericType [|t|]
                    else 
                        t
                let value = serializer.Deserialize(reader, t)
                if value <> null then
                    FSharpValue.MakeUnion(cases.[1], [|value|])
                else
                    FSharpValue.MakeUnion(cases.[0], [||])

